!pip install plotly
import plotly
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import pandas as pd
Мы будем использовать оффлайн версию. Если вы хотите хранить графики в облаке, используйте
https://plot.ly/python/getting-started/#chart-studio-support
Вам понадобится регистрация и создание своего API ключа.
Синтаксис plotly несколько отличается от того, что мы уже видели в matplotlib.
Здесь мы передаем данные для графиков функция из библиотеки plotly.graph_objects, которую мы импортировали как go, и потом эти графики передаем функции go.Figure, которая собственно рендерит наш график.
our_data = [2, 3, 1] # задаем данные
our_bar = go.Bar(y = our_data) # передаем данные объекту Bar, говорим, что наши данные, это величина категории по шкале y
fig = go.Figure(our_bar) # передаем наш бар объекту Figure, который уже рисует график (ура, что-то знакомое!)
fig.show() # выводим график
А теперь давайте представим, что наши данные разбиты по какой-то категориальной переменной.
trace0 = go.Bar(y = [2, 3, 1])
trace1 = go.Bar(y = [4, 7, 3])
our_data = [trace0, trace1] # когда объектов больше одного - передаем их списком
fig = go.Figure(our_data)
fig.show()
Теперь попробуем построить что-то с координатами x и y. Такой график уже будет Scatter - у каждого нашего наблюдения есть координаты x и y.
trace0 = go.Scatter(
x=[1, 2, 3, 4],
y=[10, 15, 13, 17]
)
trace1 = go.Scatter(
x=[1, 2, 3, 4],
y=[16, 5, 11, 9]
)
our_data = [trace0, trace1]
fig = go.Figure(our_data)
fig.update_layout(width=800, height=800)
fig.show()
#fig.write_image("fig1.png")
Давайте теперь попробуем построить пару уже знакомых нам графиков для обитателей леса.
forest = pd.read_csv('https://raw.githubusercontent.com/aaparshina/DDC_22-23_basics_python/main/data/populations.txt', sep = '\t')
forest.head()
# упражнение 1
trace_hare = go.Scatter(
x=forest.year,
y=forest.hare
)
trace_carrot = go.Scatter(
x=forest.year,
y=forest.carrot
)
our_data = [trace_hare, trace_carrot]
fig = go.Figure(our_data)
fig.show()
# упражнение
trace_all = go.Bar(
x=forest.year,
y=forest.hare + forest.lynx + forest.carrot
)
trace_lynx = go.Bar(
x=forest.year,
y=forest.lynx
)
our_data = [trace_all, trace_lynx]
fig = go.Figure(our_data)
fig.show()
А теперь давайте построим эти два графика рядом.
Обратите внимание, plotly считает с 1, а не с 0, как мы привыкли.
fig = make_subplots(rows=2, cols=1)
fig.add_trace(trace_carrot, row=1, col=1)
fig.add_trace(trace_hare, row=1, col=1)
fig.add_trace(trace_all, row=2, col=1)
fig.add_trace(trace_lynx, row=2, col=1)
В plotly за данные внутри оси координаты и всю "красоту" (подписи, шкалы, фон, сетка и т.д.) отвечают два разных объекта - data и layout.
'fig = go.Figure(data = our_data)'
Здесь объект data принимает данные, из которых figure построит нам график. Как мы увидим ниже, аттрибуты данных тоже настраиваются объекте данных (например, цвет или размер точек).
За внешний вид этого графика отвечает layout - там довольно много параметров, которые можно настроить, которые задаются через словари, где ключ - параметр, а значение - то, как мы хотим его изменить (текст, числовое значение и т.д.).
https://plot.ly/python/reference/ - здесь можно посмотреть, какие типы графиков вообще есть и какие параметры можно настраивать в каждом из них.
В объект layout мы передаем словарь, где ключ - ключевое слово, а значение - то, что мы ему присваиваем. Обратите внимание, в синтаксе ниже показаны три варианта, как это можно записать. Все они эквивалентны.
trace0 = go.Scatter(
x=[1, 2, 3, 4],
y=[10, 15, 13, 17]
)
our_data = [trace0]
our_layout = dict(title = 'A simple line')
# our_layout = {'title' : 'A simple line'}
# our_layout = go.Layout(title = 'A simple line')
# после того, как создали отдельно объекты и для data, и для layout, передаем их функции go.Figure()
fig = go.Figure(data=our_data, layout=our_layout)
fig.show()
Как уже говорилось, все, что внутри осей координат и касается данных - настраивается внутри объекта, относящимся к данным. Так в объекте go.Scatter (который по сути создает словарь, вообще почти все в plotly построено на синтаксисе словарей) мы можем прописать тип, цвет и размер маркеров, всплывающий текст и т.д.). В layout подписываем шкалы x и y - обратите внимание, что внутри словаря некторые параметры в свою очередь тоже словари :)
trace0 = go.Scatter(
x=[1, 2, 3, 4],
y=[10, 15, 13, 17],
marker={'color': 'red', 'symbol': 'x-open', 'size': 10}, # аттрибуты маркера - цвет, код символа, размер
mode = 'lines+markers', # атрибуты графика. Здесь можно задать просто линию или маркеры, например
text = ['one', 'two', 'three', 'four'], # подписи к точкам
name = 'Red Trace' # имя в легенде
)
our_data = [trace0]
our_layout = go.Layout(
title="First Plot",
xaxis={'title':'x axis'}, # заголовки шкал
yaxis={'title':'y axis'})
# после того, как создали отдельно объекты и для data, и для layout, передаем их функции go.Figure()
fig = go.Figure(data=our_data, layout=our_layout)
fig.show()
Давайте посмотрим, как наши объекты выглядят внутри
# словари словарей!
our_data
# при желании мы даже можем обратиться к объектам внутри по индексу
our_data[0]['marker']['color']
our_layout
trace_hare = go.Scatter(
x=forest.year,
y=forest.hare,
marker={'color': 'grey'},
name = 'Hares'
)
trace_carrot = go.Scatter(
x=forest.year,
y=forest.carrot,
marker={'color': 'orange'},
name = 'Carrots'
)
trace_lynx = go.Scatter(
x=forest.year,
y=forest.lynx,
marker={'color': 'teal'},
name = 'Lynxes'
)
our_data = [trace_hare, trace_carrot, trace_lynx]
our_layout = go.Layout(
title="Who is living in the forest?",
xaxis={'title':'years'},
yaxis={'title':'population'})
fig = go.Figure(data = our_data, layout = our_layout)
fig.show()
Цвет, размер, прозрачность и цветовая схема указываются в словаре аттрибутов маркера (size, color, opacity, colorscale, showscale).
crimes = pd.read_csv('https://raw.githubusercontent.com/aaparshina/DDC_22-23_basics_python/main/data/crimeRatesByState2005.tsv', sep = '\t')
crimes.head()
trace0 = go.Scatter(
x = crimes['murder'],
y = crimes['burglary'],
mode = 'markers',
marker = dict(size = crimes['population']/500000,
color = crimes['motor_vehicle_theft'],
opacity = 0.7,
colorscale ='Electric',
showscale =True),
text = crimes['state'],
hovertemplate =
'<b>%{text}</b>' +
'<br><i>Murders per capita</i>: %{x}' +
'<br><i>Burglary per capita</i>: %{y}' +
'<br><i>Motor Vehicle Theft per capita</i>: %{marker.color}' +
'<br><i>Population</i>: %{marker.size}'
)
layout= go.Layout(
title= 'Crime in the USA',
xaxis= dict(
title= 'Murder rate (number per 100,000 population)',
gridwidth= 2,
),
yaxis=dict(
title= 'Burglary rate (number per 100,000 population)',
gridwidth= 2,
),
)
fig = go.Figure(data = [trace0], layout = layout)
fig
Сделай график рассеяния для данных gapminder.
gapminder = pd.read_csv('https://raw.githubusercontent.com/aaparshina/DDC_22-23_basics_python/main/data/gapminderData.csv')
gapminder.head()
import numpy as np
gapminder['log_gdpPercap'] = np.log(gapminder['gdpPercap'])
gapminder['continent'] = pd.Categorical(gapminder['continent'])
gapminder.head()
gapminder_1972 = gapminder[gapminder['year'] == 1972]
trace0 = go.Scatter(
x = gapminder_1972['log_gdpPercap'],
y = gapminder_1972['lifeExp'],
mode = 'markers',
marker = dict(size = gapminder_1972['pop']/5000000,
color = gapminder_1972['continent'].cat.codes,
opacity = 0.7,
colorscale ='Viridis',
showscale =False),
text = gapminder_1972['country'],
hovertemplate =
'<b>%{text}</b>' +
'<br><i>GDG per Capita</i>: %{x}' +
'<br><i>Life Expectancy</i>: %{y}' +
"<extra></extra>",
)
layout = go.Layout(
title='Life Expectancy v. Per Capita GDP in 1972',
hovermode='closest',
xaxis=dict(
title='GDP per capita',
gridwidth=2,
),
yaxis=dict(
title='Life Expectancy (years)',
gridwidth=2,
),
)
fig = go.Figure(data = [trace0], layout = layout)
fig
#fig.write_image("fig1.png")
На самом деле ценность данных gapminder, что их здорово использовать для создания анимаций. В традиционном синтаксе Plotly это можно сделать, но сейчас мы воспользуемся библиотекой plotly.express.
https://plot.ly/python/plotly-express/
Это библиотека, которая специально была сделана для "быстрых" визуализаций. Я думаю, вы заметили, что синтаксис plotly достаточно громоздкий по сравнению с matplotlib. Но он и более гибкий. Plotly.express больше похожа на matplotlib, и анимацию мы сделаем именно в ней, потому что здесь это сильно проще.
Ниже ссылку, как делать анимации в традиционном plotly
import plotly.express as px
# какая переменная отвечает за анимацию?
px.scatter(gapminder, x="gdpPercap", y="lifeExp", animation_frame="year",
size="pop", color="continent", hover_name="country",
log_x=True, size_max=55, range_x=[100,100000], range_y=[25,90])
Также в plotly можно создавать интерактивные тепловые карты. Для этого используем функцию Choropleth.
Параметр location mode принимает значения, которые будут отвечать за географические данные, а locations - уже собственно переменную. Если у вас есть набор данных, где колонка с географическими словарями совпадает с внутренним словарем plotly, то даже почти ничего не нужно делать, все распознается автоматически.
Параметр z - данные, которые наносим на тепловую шкалу.
Почитать больше про тепловые карты: https://plot.ly/python/choropleth-maps/
И про все виды интерактивных карт в plotly: https://plot.ly/python/maps/
trace0 = go.Choropleth(
locationmode = 'country names',
locations = gapminder_1972['country'],
text = gapminder_1972['country'],
z = gapminder_1972['lifeExp']
)
fig = go.Figure(data = [trace0])
fig
Постройте график для ирисов. Каждый тип ирисов должен быть отдельным графиком, объединенными в один. Длина чашелистика (sepal) - шкала x, длина лепестка (petal) - шкала y, размер маркера - ширина лепестка, цвет - тип ирисов.
iris = pd.read_csv('https://raw.githubusercontent.com/aaparshina/DDC_22-23_basics_python/main/data/iris.csv', header = 0)
iris.head()
iris.species.unique()
setosa = iris[iris.species == 'setosa']
versicolor = iris[iris.species == 'versicolor']
virginica = iris[iris.species == 'virginica']
trace1 = go.Scatter(
x = setosa['sepal_length'],
y = setosa['sepal_width'],
mode = 'markers',
marker = dict(size = setosa["petal_length"]*10,
color = '#FF0000'),
name = 'iris setosa'
)
trace2 = go.Scatter(
x = versicolor['sepal_length'],
y = versicolor['sepal_width'],
mode = 'markers',
marker = dict(size = versicolor["petal_length"]*10,
color = '#009900'),
name = 'iris versicolor'
)
trace3 = go.Scatter(
x = virginica['sepal_length'],
y = virginica['sepal_width'],
mode = 'markers',
marker = dict(size = virginica["petal_length"]*10,
color = '#3333FF'),
name ='iris virginica'
)
layout= go.Layout(
title= 'Iris clustering',
hovermode= 'closest',
xaxis= dict(
title= 'Sepal Length (in cm)',
gridwidth= 2,
),
yaxis=dict(
title= 'Sepal width (in cm)',
gridwidth= 2,
),
showlegend= True
)
data = [trace1, trace2, trace3]
fig = go.Figure(data=data, layout=layout)
fig.show()